/*  Init
 *
 *  need more description
 *
 *  Input parameters:  NONE
 *
 *  Output parameters:  NONE
 *
 *  COPYRIGHT (c) 1989-1999.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  $Id: init.c,v 1.15 2008/01/11 22:50:10 joel Exp $
 */

#define CONFIGURE_INIT
#include "system.h"
#include <stdio.h>
#include <rtems/libio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <rtems/posix/mman.h>
#include <libcpu/page.h>
#include <rtems/error.h>
#include <libcpu/spr.h>
#include <errno.h>

  char *bufr = "Most modern processors have MMU Hardware (Memory Management Unit) whose main functions "
                      "are virtual address translation, memory protection and cache control. With RTEMS primarily "
                      "focused on Embedded Real Time applications, making use of these MMU features especially "
                      "memory Protection is important to meet the needs of those Embedded Real Time applications "
                      "that requires such support. The goal of this project is to implement an architecture independent API "
                      "and structure to manage memory blocks with access attribute based on MMU Support. ";

  int src_fd,dst_fd;
  char * src_filename = "srcfile", * dst_filename = "dstfile";
  
  char src_buf[0x1000] __attribute__ ((aligned ( PAGE_SIZE )));
  char dst_buf[0x1000] __attribute__ ((aligned ( PAGE_SIZE )));
  struct stat	statbuf;
  
rtems_task maptask2(rtems_task_argument ignored);
rtems_task maptask3(rtems_task_argument ignored);
rtems_task maptask4(rtems_task_argument ignored);


rtems_task Init(
  rtems_task_argument ignored
)
{
 rtems_id   Task_id;         /* array of task ids */
 rtems_name Task_name;       /* array of task names */
  rtems_status_code status;

  char  *chbuf;
  int n , i ;

/*creat the source file */
  printf("create an source file.\n", n);
  src_fd = creat (src_filename, S_IRWXU | S_IRWXG | S_IRWXO);
  n=write(src_fd, bufr, strlen(bufr) );
  if(src_fd < 0 || n <= 0)
  {
    puts("create and write failed.  test exit");
    exit(0);
  }
  else close(src_fd);
  printf("create an empty destination file.\n", n);
  dst_fd = creat (dst_filename, S_IRWXU | S_IRWXG | S_IRWXO);
  if(dst_fd <0)
  {
    puts("create file failed. test exit");
    exit(0);
  }
  else close(dst_fd);

  /*check :print the source file*/
  chbuf = (char*)malloc(1000);
  for(i=0;i<1000;i++)
  	chbuf[i] = '\0';
  src_fd = open ( src_filename , O_RDWR);
  read(src_fd, chbuf, n);
  chbuf[n+1] = '\0';
  printf("source file:  %s\n\n", chbuf);
  free(chbuf);

  puts( "\n*** MMU POSIX API TEST  BEGINS ***\n" );

  memset(src_buf, 0, 0x1000);
  memset(dst_buf, 0, 0x1000);
  if( (src_fd = open ( src_filename , O_RDONLY)) <1 )
  	rtems_panic("can't open %s for reading", src_filename);
  if( (dst_fd = open ( dst_filename , O_RDWR)) <1 )
    rtems_panic("can't open %s for reading", dst_filename);  

  if (fstat(src_fd, &statbuf) < 0)  /* need size of input file */
    rtems_panic("fstat error");

  /* set size of output file */
  if (lseek(dst_fd, statbuf.st_size - 1, SEEK_SET) == -1)
    rtems_panic("lseek error");
  if (write(dst_fd, "", 1) != 1)
    rtems_panic("write error");
    
  puts("Map files to memory buffers.");
  if (( mmap(src_buf, statbuf.st_size, PROT_READ | PROT_WRITE, 
    MAP_PRIVATE|MAP_FIXED,    src_fd, 0)) == MAP_FAILED)
  {
    printf("source file mmap error , errno = 0x%x\n", errno);
    exit(0);
  }

  if (( mmap(dst_buf, statbuf.st_size, PROT_READ | PROT_WRITE,
    MAP_PRIVATE|MAP_FIXED,  dst_fd, 0)) == MAP_FAILED)
  {
    printf("destination file mmap error , errno = 0x%x\n", errno);
    exit(0);
  }

  puts("test1: should print the file content normally:");
  memcpy(dst_buf, src_buf, statbuf.st_size); 
  printf("dst_buf:%s\ncopy successfully!\n", dst_buf);


  /*test 2*/
  Task_name = rtems_build_name( 'T', 'A', '2', ' ' );
  status = rtems_task_create(
     Task_name,
     1,
     TASK_STACK_SIZE,
     RTEMS_DEFAULT_MODES,
     RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT,
     &Task_id
  );
  status = rtems_task_start( Task_id, maptask2, 0 );
  
  while(rtems_task_is_suspended(Task_id)!=RTEMS_INVALID_ID)
    sleep(10);

  /*test 3*/
  Task_name = rtems_build_name( 'T', 'A', '3', ' ' );
  status = rtems_task_create(
     Task_name,
     1,
     TASK_STACK_SIZE,
     RTEMS_DEFAULT_MODES,
     RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT,
     &Task_id
  );
  status = rtems_task_start( Task_id, maptask3, 0 );

  while(rtems_task_is_suspended(Task_id)!=RTEMS_INVALID_ID)
    sleep(10);

  /*test 4*/
  Task_name = rtems_build_name( 'T', 'A', '4', ' ' );
  status = rtems_task_create(
     Task_name,
     1,
     TASK_STACK_SIZE,
     RTEMS_DEFAULT_MODES,
     RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT,
     &Task_id
  );
  status = rtems_task_start( Task_id, maptask4, 0 );

  while(rtems_task_is_suspended(Task_id)!=RTEMS_INVALID_ID)
    sleep(10);

  exit(0);
}

rtems_task maptask2(
rtems_task_argument ignored
)
{
  puts("\ntest 2 : write to the ReadOnly mapped address");

  memset(dst_buf, 0, 0x1000);
  /*reset the map protect attribute*/
  puts("call mprotect to forbidden write to dst_buf .");
  if( 0 != mprotect(dst_buf, 0x1000, PROT_READ)){
    printf("mprotect failed,errno = %d", errno);
    rtems_task_delete(RTEMS_SELF);
  }

  puts("test2: wtire should be denied :");
  memcpy(dst_buf, src_buf, statbuf.st_size); 
  puts("test2 failed: this line should never be printed");
  printf("dst_buf:%s\n", dst_buf);
  close(src_fd);
  close(dst_fd);
  /*exit this task*/
  rtems_task_delete(RTEMS_SELF);
}


rtems_task maptask3(
rtems_task_argument ignored
)
{
  char c;
  puts("\ntest 3 : read the mapped address with PROT_NONE attribute( un-accessable)");

  memset(dst_buf, 0, 0x1000);
  /*reset the map protect attribute*/
  puts("call mprotect to forbidden read/write to dst_buf now.");
  if( 0 != mprotect(dst_buf, 0x1000, PROT_NONE)){
    printf("mprotect failed,errno = %d", errno);
    rtems_task_delete(RTEMS_SELF);
  }

  puts("test3, read should be denied :");
  c = dst_buf[0];
  puts("test3 failed: this line should never be printed");
  close(src_fd);
  close(dst_fd);
  /*exit this task*/
  rtems_task_delete(RTEMS_SELF);

}

rtems_task maptask4(
rtems_task_argument ignored
)
{
  puts("\ntest 4 : set  the  mapped address with WRITEONLY attribute. "
          " This should failed for psim because hardware don't support WRITEONLY. ");

  /*reset the map protect attribute*/
  puts("reset  dst_buf  the attribute  now.");
  if( 0 != mprotect(dst_buf, 0x1000, PROT_WRITE)){
    printf("mprotect failed,errno = %d\n", errno);
    rtems_task_delete(RTEMS_SELF);
  }

  puts("test4 failed:mprotect success");
  close(src_fd);
  close(dst_fd);
  /*exit this task*/
  rtems_task_delete(RTEMS_SELF);
}


